package org.jaaksi.gradleplugindemo.compiler;

import java.util.Iterator;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import org.jaaksi.gradleplugindemo.annotation.Route;
import org.jaaksi.gradleplugindemo.compiler.util.Logger;

/**
 * @AutoService(Processor.class)，自动生成 META-INF 信息；
 * @SupportedAnnotationTypes({"com.example.BindView"})，声明 Processor 处理的注解，注意这是一个数组，表示可以处理多个注解；
 * @SupportedSourceVersion(SourceVersion.RELEASE_7)，声明支持的源码版本
 * @SupportedAnnotationTypes 和 @SupportedSourceVersion 必须声明，否则会报错
 * 除了注解方式，你也可以通过重写对应的两个函数实现
 */
@SupportedAnnotationTypes({ "org.jaaksi.gradleplugindemo.annotation.Route" })
public class RouteProcessor extends AbstractProcessor {
  private Logger logger;
  private int round;

  @Override
  public SourceVersion getSupportedSourceVersion() {
    return SourceVersion.latest();
  }

  //@Override public Set<String> getSupportedAnnotationTypes() {
  //  Set<String> annotataions = new LinkedHashSet<String>();
  //  annotataions.add(Route.class.getCanonicalName());
  //  return annotataions;
  //}

  /**
   * 这个方法在整个编译期间仅仅被调用一次，作用就是初始化参数ProcessingEnvironment
   */
  @Override public synchronized void init(ProcessingEnvironment processingEnvironment) {
    super.init(processingEnvironment);
    logger = new Logger(processingEnvironment.getMessager());
  }

  /**
   * 注解处理器新生成出来的类就是在这个方法生成的。之前我们说过ProcessingEnvironment是包含了注解处理器相关的工具类和编译器配置的参数，
   * 而RoundEnvironment则是指在每一轮的扫描和处理源代码中获取被注解的Element
   */
  @Override
  public boolean process(Set<? extends TypeElement> annotations,
    RoundEnvironment roundEnvironment) {

    String resultPath =
      processingEnv.getOptions().get("org.jaaksi.gradleplugindemo.annotation.Route");
    if (resultPath == null) {
      logger.error("No option Route passed to annotation processor");
      return false;
    }

    round++;
    logger.info("round " + round + " process over " + roundEnvironment.processingOver());

    Iterator<? extends TypeElement> iterator = annotations.iterator();
    while (iterator.hasNext()) {
      logger.info("name is " + iterator.next().getSimpleName().toString());
    }

    if (roundEnvironment.processingOver()) {
      if (!annotations.isEmpty()) {
        logger.error(
          "Unexpected processing state: annotations still available after processing over");
        return false;
      }
    }

    if (annotations.isEmpty()) {
      return false;
    }

    Set<? extends Element> elements =
      roundEnvironment.getElementsAnnotatedWith(Route.class);
    if (elements == null || elements.isEmpty()) {
      return true;
    }

    // 合法的TypeElement集合
    //Set<TypeElement> typeElements = new HashSet<>();
    //for (Element element : elements) {
    //  if (element.getKind().isClass() && validateClass((TypeElement) element)) { // 注解在Class上的Route
    //    typeElements.add((TypeElement) element);
    //  } else if (element.getKind() == ElementKind.METHOD) { // 注解在Method上的Route
    //    validateMethod((ExecutableElement) element);
    //  }
    //}
    logger.info(String.format(">>> %s: RouteProcessor begin... <<<", ""));
    return false;
  }

/**
 * Verify the annotated class. Must be a subtype of Activity or Fragment.
 */
//private boolean validateClass(TypeElement typeElement) {
//  if (!isSubtype(typeElement, ACTIVITY_FULL_NAME) && !isSubtype(typeElement,
//    FRAGMENT_V4_FULL_NAME)
//    && !isSubtype(typeElement, FRAGMENT_FULL_NAME)) {
//    mLogger.error(typeElement, String.format("%s is not a subclass of Activity or Fragment.",
//      typeElement.getSimpleName().toString()));
//    return false;
//  }
//  Set<Modifier> modifiers = typeElement.getModifiers();
//  // abstract class.
//  if (modifiers.contains(Modifier.ABSTRACT)) {
//    mLogger.error(typeElement,
//      String.format("The class %s is abstract. You can't annotate abstract classes with @%s.",
//        (typeElement).getQualifiedName(), Route.class.getSimpleName()));
//    return false;
//  }
//  return true;
//}
}
